import datetime
from itertools import groupby

from odoo import api, models, fields, _, Command
from odoo.exceptions import ValidationError
from odoo.tools import float_compare


class SbReworkCheck(models.Model):
    _name = 's.rework.check'
    _inherit = ["mail.thread", "portal.mixin", "mail.activity.mixin"]
    _description = "Rework Check"
    """
    1、选批次+物料
    2、选检修流程
    3、确认检修，生产检修工单
    4、检修完成之后检修入库，和报废专业
    5、对于原库存数量需要进行库存转移操作
    """

    name = fields.Char('Name', copy=False, readonly=True, index=True, default='New', required=True)
    lot_ids = fields.Many2many('stock.lot', string='Lot')
    product_id = fields.Many2one('product.product', string='Product')
    rework_bom_id = fields.Many2one('s.rework.bom', string='rework bom')
    production_id = fields.Many2one('mrp.production', string='Rework Check Order')
    state = fields.Selection([
        ('draft', 'Draft'),
        ('production', 'Production'),
        ('cancel', 'Cancel')
    ], default='draft', string='Status')
    picking_ids = fields.One2many('stock.picking', 'sb_rework_check_id', 'Picking')
    line_ids = fields.One2many('s.rework.check.line', 'check_id', string='Lines')

    @api.onchange('line_ids')
    def onchange_lot_ids(self):
        for obj in self:
            obj.lot_ids = [(6, 0, [line.lot_id.id for line in obj.line_ids if line.lot_id])]

    @api.onchange('product_id')
    def onchange_name(self):
        if self.product_id:
            self.line_ids = [Command.clear()]
            self.lot_ids = None
            rework_bom_ids = self.env['s.rework.bom'].search([('product_id', '=', self.product_id.id)])
            if rework_bom_ids and len(rework_bom_ids) == 1:
                self.rework_bom_id = rework_bom_ids.id

            quant_ids = self.env['stock.quant'].search([
                ('product_id', '=', self.product_id.id),
                ('quantity', '>', 0),
                ('location_id.usage', '=', 'internal')
            ])

            line_vals = []
            for quant in quant_ids:
                line_vals.append((0,0, {
                    'lot_id': quant.lot_id.id,
                    'location_id': quant.location_id.id,
                    'available_quantity': quant.quantity,
                    'uom_id': quant.product_id.uom_id.id
                }))
            self.line_ids = line_vals
        else:
            self.line_ids = [Command.clear()]

    def create_rework(self):
        qty = sum(self.line_ids.mapped('qty'))
        if not qty:
            raise ValidationError(_('Maintenance quantity must be greater than 0'))

        for line in self.line_ids:
            if float_compare(line.available_quantity, line.qty, precision_rounding=line.uom_id.rounding) == -1:
                raise ValidationError(_('The overhaul quantity cannot be greater than the inventory quantity!'))

        # if self.product_id.value_set and (qty % self.product_id.value_set):
        #     raise ValidationError(_('SET / PCS out of proportion!'))

        motypestr = _("Rework")
        prod = self._create_rework_production()
        # prod.name = prod.name.replace('P', 'W', 1)
        prod.action_confirm()
        self.create_picking()
        body = motypestr + " : " + prod.name + "\n"
        self.message_post(body=body or "")
        self.update({
            "state": 'production',
            "production_id": prod.id
        })
        return {
            'name': _('Production Order'),
            'type': 'ir.actions.act_window',
            'res_model': 'mrp.production',
            'view_mode': 'tree,form',
            'target': 'current',
            'views': [[False, 'tree'], [False, 'form']],
            'context': {'create': False},
            'domain': [('id', 'in', [prod.id])],
        }

    def _create_rework_production(self):
        picking_type = self.env['stock.picking.type'].search([('code', '=', 'mrp_operation')], limit=1)
        location_id = self.env['stock.location'].search([('barcode', '=', 'WH-REPAIR')], limit=1)
        if not location_id:
            raise ValidationError(_('Location not found, Please contact the administrator'))
        qty = sum(self.line_ids.mapped('qty'))
        vals = {
            'mo_type': 'W',
            'product_id': self.product_id.id,
            'bom_id': None,
            'picking_type_id': picking_type.id,
            'location_src_id': location_id.id,
            'product_qty': qty,
            'product_uom_id': self.product_id.uom_id.id,
            'user_id': self.env.user.id,
            'origin': 'ReworkCheck' + '/' + str(self.id),
            'is_rework_check': True,
            's_order_type': 'R',
            'move_raw_ids': [(0, 0, {
                'company_id': self.env.user.company_id.id,
                'date': datetime.datetime.now(),
                'location_dest_id': picking_type.default_location_dest_id.id,
                'location_id': location_id.id,
                'name': self.product_id.display_name,
                'procure_method': 'make_to_stock',
                'product_id': self.product_id.id,
                'product_uom':  self.product_id.uom_id.id,
                'product_uom_qty': qty,
                'unit_factor': 1,
            })],
        }
        body = ""
        prod = self.env['mrp.production'].with_user(self.env.user).sudo().with_company(self.env.company.id).create(vals)
        body += _("Rework-") + " : " + prod.name + "\n"
        # 根据检修bom，更新检修工序
        # 检修，不需要物料消耗
        # prod.move_raw_ids = [Command.clear()]
        # prod.mapped('workorder_ids').unlink()
        if not self.rework_bom_id.line_ids.filtered(lambda x: x.workcenter_id.code == 'PKG01'):
            # 检修没有包装流程时自动加上包装工序
            pack_workcenter_id = self.env['mrp.workcenter'].search([('code', '=', 'PKG01')], limit=1)
            step = len(self.rework_bom_id.line_ids) + 1
            s = '%02d' % step
            name = s + '.' + pack_workcenter_id.display_name.strip()
            work_station_id = pack_workcenter_id.work_station_id.id
            self.env['s.remork.bom.line'].create([{
                'step': len(self.rework_bom_id.line_ids) + 1,
                'name': name,
                'work_station_id': work_station_id,
                'workcenter_id': pack_workcenter_id.id,
                'rework_bom_id': self.rework_bom_id.id
            }])

        workorder_vals_list = []
        for bom_line in self.rework_bom_id.line_ids:
            workorder_vals_list.append({
                'name': bom_line.name,
                'workcenter_id': bom_line.workcenter_id.id,
                # 'rma_operation_id': bom_line.id,
                'production_id': prod.id,
                'product_uom_id': self.product_id.uom_id.id,
                'step': bom_line.step
            })
        self.env['mrp.workorder'].create(workorder_vals_list)

        raw_move_ = prod.move_raw_ids[0]
        move_line_vals_list = []
        for lot, g in groupby(self.line_ids.sorted(lambda x: x.lot_id.id), key=lambda x: x.lot_id):
            g_line = self.env['s.rework.check.line'].concat(*g)
            raw_move_vals = raw_move_._prepare_move_line_vals(sum(g_line.mapped('qty')))
            raw_move_vals.update({
                'lot_id': lot.id,
                'picked': True,
            })
        self.env['stock.move.line'].create(move_line_vals_list)
        return prod

    def create_picking(self):
        """
        创建调拨
        """
        location_id = self.env['stock.location'].search([('barcode', '=', 'WH-STOCK-FINISHED-PRODUCT')], limit=1)
        location_dest_id = self.env['stock.location'].search([('barcode', '=', 'WH-PREPRODUCTION')], limit=1)
        production_location_ids = location_dest_id + location_dest_id.child_ids
        picking_type = self.env['stock.picking.type'].search([('barcode', '=', 'WTT-INTERNAL-REWORK')], limit=1)
        move_line_vals_list = []

        picking_line_ids = self.line_ids.filtered(lambda x: x.qty > 0 and x.location_id not in production_location_ids)
        if not picking_line_ids:
            return

        picking_vals = {
            'company_id': self.env.user.company_id.id,
            'location_id': location_id.id,
            'location_dest_id': picking_type.default_location_dest_id.id,
            'sb_rework_check_id': self.id,
            'picking_type_id': picking_type.id,
            'move_ids': [(0, 0, {
                'name': self.product_id.name,
                'product_id': self.product_id.id,
                'location_id': location_id.id,
                'location_dest_id': picking_type.default_location_dest_id.id,
                'product_uom_qty': sum(picking_line_ids.mapped('qty')),
            })],
        }
        picking = self.env['stock.picking'].sudo().create(picking_vals)
        move_id = picking.move_ids[0]
        for line in picking_line_ids:
            move_line_vals = move_id._prepare_move_line_vals(line.qty)
            move_line_vals.update({'lot_id': line.lot_id.id, 'picked': True})
            move_line_vals_list.append(move_line_vals)
        self.env['stock.move.line'].create(move_line_vals_list)
        picking.action_confirm()
        return picking

    @api.model_create_multi
    def create(self, vals_list):
        for vals in vals_list:
            if vals.get('name', "New") == "New":
                vals['name'] = self.env['ir.sequence'].next_by_code('s.rework.check') or "New"

        return super().create(vals_list)

    def action_cancel(self):
        self.state = 'cancel'

    def action_view_mrp_production(self):
        return {
            'name': _('Production Order'),
            'type': 'ir.actions.act_window',
            'res_model': 'mrp.production',
            'view_mode': 'tree,form',
            'target': 'current',
            'views': [[False, 'tree'], [False, 'form']],
            'context': {'create': False},
            'domain': [('id', 'in', [self.production_id.id])],
        }

    def action_view_stock_picking(self):
        return {
            'name': _('Picking'),
            'type': 'ir.actions.act_window',
            'res_model': 'stock.picking',
            'view_mode': 'tree,form',
            'target': 'current',
            'views': [[False, 'tree'], [False, 'form']],
            'context': {'create': False},
            'domain': [('id', 'in', self.picking_ids.ids)],
        }


class SbReworkCheckLine(models.Model):
    _name = 's.rework.check.line'
    _description = 'Rework Check Line'
    _order = 'location_id desc'

    check_id = fields.Many2one('s.rework.check')
    lot_id = fields.Many2one('stock.lot', string='lot')
    location_id = fields.Many2one('stock.location', 'location')
    available_quantity = fields.Float(string='repairable quantity')
    qty = fields.Float(string='maintenance quantity')
    is_active = fields.Boolean(string='is maintenance')
    uom_id = fields.Many2one('uom.uom', 'Uom')

    @api.onchange('lot_id')
    def _compute_available_qty(self):
        for rec in self:
            available_quantity = 0
            for quant in rec.lot_id.mapped('quant_ids').filtered(lambda x: x.location_id.usage == 'internal'):
                available_quantity += quant.available_quantity
            rec.available_quantity = available_quantity
